#ifndef SYSCALL_API_H
#define SYSCALL_API_H

#include "SVF/Util/BasicTypes.h"

typedef std::set<std::string> StringSet;

/***
 * Provides all functions and information to handle system calls.
 */
class SyscallAPI {
public:
	enum SYS_TYPE {
		SYS_READ, SYS_WRITE, SYS_OPEN, SYS_CLOSE, SYS_NEWSTAT, SYS_NEWFSTAT, SYS_NEWLSTAT, 
		SYS_POLL, SYS_LSEEK, SYS_MMAP, SYS_MPOTECT, SYS_MUNMAP, SYS_BRK, SYS_RT_SIGACTION, 
		SYS_RT_SIGPROCMASK, SYS_RT_SIGRETURN, SYS_IOCTL, SYS_PREAD64, SYS_PWRITE64, 
		SYS_READV, SYS_WRITEV, SYS_ACCESS, SYS_PIPE, SYS_SELECT, SYS_SCHED_YIELD, 
		SYS_MREMAP, SYS_MPROTECT, SYS_MSYNC, SYS_MINCORE, SYS_MADVISE, SYS_SHMGET, SYS_SHMAT, SYS_SHMCTL, 
		SYS_DUP, SYS_DUP2, SYS_PAUSE, SYS_NANOSLEEP, SYS_GETITIMER, SYS_ALARM, 
		SYS_SETITIMER, SYS_GETPID, SYS_SENDFILE64, SYS_SOCKET, SYS_CONNECT, SYS_ACCEPT, 
		SYS_SENDTO, SYS_RECVFROM, SYS_SENDMSG, SYS_RECVMSG, SYS_SHUTDOWN, SYS_BIND, 
		SYS_LISTEN, SYS_GETSOCKNAME, SYS_GETPEERNAME, SYS_SOCKETPAIR, SYS_SETSOCKOPT, 
		SYS_GETSOCKOPT, SYS_CLONE, SYS_FORK, SYS_VFORK, SYS_EXECVE, SYS_EXIT, SYS_WAIT4, 
		SYS_KILL, SYS_NEWUNAME, SYS_SEMGET, SYS_SEMOP, SYS_SEMCTL, SYS_SHMDT, SYS_MSGGET, 
		SYS_MSGSND, SYS_MSGRCV, SYS_MSGCTL, SYS_FCNTL, SYS_FLOCK, SYS_FSYNC, SYS_FDATASYNC, 
		SYS_TRUNCATE, SYS_FTRUNCATE, SYS_GETDENTS, SYS_GETCWD, SYS_CHDIR, SYS_FCHDIR, 
		SYS_RENAME, SYS_MKDIR, SYS_RMDIR, SYS_CREAT, SYS_LINK, SYS_UNLINK, SYS_SYMLINK, 
		SYS_READLINK, SYS_CHMOD, SYS_FCHMOD, SYS_CHOWN, SYS_FCHOWN, SYS_LCHOWN, SYS_UMASK, 
		SYS_GETTIMEOFDAY, SYS_GETRLIMIT, SYS_GETRUSAGE, SYS_SYSINFO, SYS_TIMES, SYS_PTRACE, 
		SYS_GETUID, SYS_SYSLOG, SYS_GETGID, SYS_SETUID, SYS_SETGID, SYS_GETEUID, SYS_GETEGID, 
		SYS_SETPGID, SYS_GETPPID, SYS_GETPGRP, SYS_SETSID, SYS_SETREUID, SYS_SETREGID, 
		SYS_GETGROUPS, SYS_SETGROUPS, SYS_SETRESUID, SYS_GETRESUID, SYS_SETRESGID, 
		SYS_GETRESGID, SYS_GETPGID, SYS_SETFSUID, SYS_SETFSGID, SYS_GETSID, SYS_CAPGET, 
		SYS_CAPSET, SYS_RT_SIGPENDING, SYS_RT_SIGTIMEDWAIT, SYS_RT_SIGQUEUEINFO, 
		SYS_RT_SIGSUSPEND, SYS_SIGALTSTACK, SYS_UTIME, SYS_MKNOD, SYS_PERSONALITY, SYS_USTAT, 
		SYS_STATFS, SYS_FSTATFS, SYS_SYSFS, SYS_GETPRIORITY, SYS_SETPRIORITY, 
		SYS_SCHED_SETPARAM, SYS_SCHED_GETPARAM, SYS_SCHED_SETSCHEDULER, SYS_SCHED_GETSCHEDULER, 
		SYS_SCHED_GET_PRIORITY_MAX, SYS_SCHED_GET_PRIORITY_MIN, SYS_SCHED_RR_GET_INTERVAL, 
		SYS_MLOCK, SYS_MUNLOCK, SYS_MLOCKALL, SYS_MUNLOCKALL, SYS_VHANGUP, SYS_MODIFY_LDT, 
		SYS_PIVOT_ROOT, SYS_SYSCTL, SYS_PRCTL, SYS_ARCH_PRCTL, SYS_ADJTIMEX, SYS_SETRLIMIT, 
		SYS_CHROOT, SYS_SYNC, SYS_ACCT, SYS_SETTIMEOFDAY, SYS_MOUNT, SYS_UMOUNT, SYS_SWAPON, 
		SYS_SWAPOFF, SYS_REBOOT, SYS_SETHOSTNAME, SYS_SETDOMAINNAME, SYS_IOPL, SYS_IOPERM, 
		SYS_INIT_MODULE, SYS_DELETE_MODULE, SYS_QUOTACTL, SYS_GETTID, SYS_READAHEAD, 
		SYS_SETXATTR, SYS_LSETXATTR, SYS_FSETXATTR, SYS_GETXATTR, SYS_LGETXATTR, SYS_FGETXATTR, 
		SYS_LISTXATTR, SYS_LLISTXATTR, SYS_FLISTXATTR, SYS_REMOVEXATTR, SYS_LREMOVEXATTR, 
		SYS_FREMOVEXATTR, SYS_TKILL, SYS_TIME, SYS_FUTEX, SYS_SCHED_SETAFFINITY, 
		SYS_SCHED_GETAFFINITY, SYS_IO_SETUP, SYS_IO_DESTROY, SYS_IO_GETEVENTS, SYS_IO_SUBMIT, 
		SYS_IO_CANCEL, SYS_LOOKUP_DCOOKIE, SYS_EPOLL_CREATE, SYS_REMAP_FILE_PAGES, 
		SYS_GETDENTS64, SYS_SET_TID_ADDRESS, SYS_RESTART_SYSCALL, SYS_SEMTIMEDOP, SYS_FADVISE64, 
		SYS_TIMER_CREATE, SYS_TIMER_SETTIME, SYS_TIMER_GETTIME, SYS_TIMER_GETOVERRUN, 
		SYS_TIMER_DELETE, SYS_CLOCK_SETTIME, SYS_CLOCK_GETTIME, SYS_CLOCK_GETRES, 
		SYS_CLOCK_NANOSLEEP, SYS_EXIT_GROUP, SYS_EPOLL_WAIT, SYS_EPOLL_CTL, SYS_TGKILL, 
		SYS_UTIMES, SYS_MBIND, SYS_SET_MEMPOLICY, SYS_GET_MEMPOLICY, SYS_MQ_OPEN, 
		SYS_MQ_UNLINK, SYS_MQ_TIMEDSEND, SYS_MQ_TIMEDRECEIVE, SYS_MQ_NOTIFY, SYS_MQ_GETSETATTR, 
		SYS_KEXEC_LOAD, SYS_WAITID, SYS_ADD_KEY, SYS_REQUEST_KEY, SYS_KEYCTL, SYS_IOPRIO_SET, 
		SYS_IOPRIO_GET, SYS_INOTIFY_INIT, SYS_INOTIFY_ADD_WATCH, SYS_INOTIFY_RM_WATCH, 
		SYS_MIGRATE_PAGES, SYS_OPENAT, SYS_MKDIRAT, SYS_MKNODAT, SYS_FCHOWNAT, SYS_FUTIMESAT, 
		SYS_NEWFSTATAT, SYS_UNLINKAT, SYS_RENAMEAT, SYS_LINKAT, SYS_SYMLINKAT, SYS_READLINKAT, 
		SYS_FCHMODAT, SYS_FACCESSAT, SYS_PSELECT6, SYS_PPOLL, SYS_UNSHARE, SYS_SET_ROBUST_LIST, 
		SYS_GET_ROBUST_LIST, SYS_SPLICE, SYS_TEE, SYS_SYNC_FILE_RANGE, SYS_VMSPLICE, 
		SYS_MOVE_PAGES, SYS_UTIMENSAT, SYS_EPOLL_PWAIT, SYS_SIGNALFD, SYS_TIMERFD_CREATE, 
		SYS_EVENTFD, SYS_FALLOCATE, SYS_TIMERFD_SETTIME, SYS_TIMERFD_GETTIME, SYS_ACCEPT4, 
		SYS_SIGNALFD4, SYS_EVENTFD2, SYS_EPOLL_CREATE1, SYS_DUP3, SYS_PIPE2, SYS_INOTIFY_INIT1, 
		SYS_PREADV, SYS_PWRITEV, SYS_RT_TGSIGQUEUEINFO, SYS_PERF_EVENT_OPEN, SYS_RECVMMSG, 
		SYS_FANOTIFY_INIT, SYS_FANOTIFY_MARK, SYS_PRLIMIT64, SYS_NAME_TO_HANDLE_AT, 
		SYS_OPEN_BY_HANDLE_AT, SYS_CLOCK_ADJTIME, SYS_SYNCFS,SYS_SENDMMSG, SYS_SETNS, 
		SYS_GETCPU, SYS_PROCESS_VM_READV, SYS_PROCESS_VM_WRITEV, SYS_KCMP, SYS_FINIT_MODULE, 
		SYS_TEST, SYS_DUMMY
	};

	typedef std::pair<SYS_TYPE, std::string> SysTypeToStrPair;
	typedef std::map<SYS_TYPE, std::string> SysTypeToStrMap;
	typedef std::map<std::string, SyscallAPI::SYS_TYPE> StrToSysTypeMap;
	typedef std::set<SYS_TYPE> SysTypeSet;
	typedef std::list<SysTypeSet> SysTypeSetList;
	typedef std::list<StringSet> StringSetList;

private:
	/**
	 * Set's up the system calls.
	 */
	void init();

	SyscallAPI() {
		init();
	}
public:
	static SyscallAPI* createSyscallAPI() {
		if(syscallAPI == nullptr)
			syscallAPI = new SyscallAPI();
		return syscallAPI;
	}

	static void releaseSyscallAPI() {
		if(syscallAPI != nullptr)
			delete syscallAPI;
		syscallAPI = nullptr;
	}

	bool isSyscall(std::string syscall) const;

	/**
	 * Returns a set of all system calls that belongs to the same file (group).
	 */
	SysTypeSet getRelatedSyscalls(std::string syscall);

	/**
	 * Returns a set of all system call names that belongs to the same file (group).
	 */
	StringSet getRelatedSyscallNames(std::string syscall);

	/** 
	 * Returns a set of all system call names given in the file.
	 */
	StringSetList getRelatedSyscallNamesByFile(std::string fileName, bool group=false);

	const SysTypeSetList& getAllSyscallGroups() const;
	const StringSetList& getAllSyscallNameGroups() const;
	const StringSetList& getAllSyscallNames() const;

	std::string getSyscallName(SYS_TYPE type) const;

	SYS_TYPE getSyscallType(std::string syscallName) const;

private:
	static SyscallAPI *syscallAPI;
	SysTypeToStrMap sysTypeToFuncNameMap;
	StrToSysTypeMap funcNameToSysTypeMap;
	SysTypeSetList syscallGroupList;
	StringSetList syscallNameGroupList;
	StringSetList syscallNames;
};

#endif // SYSCALL_API_H
